package com.conf4j;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.conf4j.annotation.Config;
import com.conf4j.kit.StrKit;
import com.conf4j.kit.ValueKit;
import com.conf4j.scaner.AbstractConfigScaner;
import com.conf4j.scaner.IConfigScanerLinstener;

/**
 * 配置管理类
 * 
 * @author dingnate
 *
 */
public class ConfigManager {
	private static transient final Logger LOG = LoggerFactory.getLogger(ConfigManager.class);
	private static HashMap<String, Method> key2Methods = new HashMap<String, Method>();
	private static HashMap<Class<?>, Object> configs = new HashMap<Class<?>, Object>();
	private static AbstractConfigScaner scaner;
	private static Properties mainProperties = new Properties();
	private static ConfigManagerScanerLinstener listener = new ConfigManagerScanerLinstener();

	static {
		try {
			scaner = (AbstractConfigScaner) Class.forName(Conf4jConfigScanerConf.ME.getClassName()).newInstance();
			scaner.addListener(listener);
		} catch (Exception e) {
			LOG.error("init scaner failed!", e);
		}
	}

	/**
	 * 开启配置扫描
	 */
	public static void startScaner() {
		if (scaner == null)
			return;
		//先阻塞扫描一次，初始化配置文件
		scaner.working();
		scaner.start();
	}

	/**
	 * 停止配置扫描
	 */
	public static void stopScaner() {
		if (scaner != null)
			scaner.stop();
	}

	/**
	 * 添加配置对象
	 * 
	 * @param config
	 */
	public static void addConfig(Object config) {
		Class<?> clazz = config.getClass();
		configs.put(clazz, config);
		String prefix = getPropertyKeyPrefix(clazz);
		for (Method method : getClassSetMethods(clazz)) {
			key2Methods.put(getKeyByMethod(prefix, method), method);
		}
	}
	/**
	 * 返回属性key的前缀
	 * @param clazz
	 * @return
	 */
	public static String getPropertyKeyPrefix(Class<?> clazz) {
		Config annotation = clazz.getAnnotation(Config.class);
		String prefix = annotation == null ? clazz.getName() : annotation.prefix();
		return prefix;
	}
	/**
	 * 获取配置对象
	 * 
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T config(Class<T> clazz) {
		T config = (T) configs.get(clazz);
		if (config != null)
			return config;
		T instance = null;
		try {
			// 初始化clazz
			instance = clazz.newInstance();
		} catch (Exception e) {
			return null;
		}
		config = (T) configs.get(clazz);
		if (config != null)
			return config;
		addConfig(instance);
		return instance;
	}

	/**
	 * 添加properties到mainProperties
	 * 
	 * @param properties
	 */
	public static void putProperties(Properties properties) {
		mainProperties.putAll(properties);
	}

	/**
	 * 根据配置全名获取配置字符串值
	 * 
	 * @param key
	 * @return
	 */
	public static String getValueByKey(String key) {
		String value = "";
		if (scaner != null)
			value = (String) scaner.getProps().get(key);
		if (StrKit.isNotBlank(value))
			return value;
		return mainProperties.getProperty(key, ValueKit.EMPTY);
	}

	/**
	 * ConfigManager的扫描监听器
	 * 
	 * @author dingnate
	 *
	 */
	private final static class ConfigManagerScanerLinstener implements IConfigScanerLinstener {
		public void onChange(String key, String propertyKey, String oldValue, String newValue) {
			// 变更mainProperties属性
			onChangeMainProperties(propertyKey, newValue);
			// 变更配置对象属性
			onChangeConfig(propertyKey, newValue);
		}

		/**
		 * 变更mainProperties属性
		 * 
		 * @param propertyKey
		 * @param newValue
		 */
		private void onChangeMainProperties(String propertyKey, String newValue) {
			if (newValue == null)
				mainProperties.remove(propertyKey);
			else
				mainProperties.put(propertyKey, newValue);
		}

		/**
		 * 变更配置对象属性
		 * 
		 * @param propertyKey
		 * @param newValue
		 */
		private void onChangeConfig(String propertyKey, String newValue) {
			Method method = key2Methods.get(propertyKey);
			if (method == null)
				return;
			Object object = configs.get(method.getDeclaringClass());
			if (object == null)
				return;
			try {
				method.invoke(object,
						newValue == null ? null : ValueKit.convert(newValue, method.getParameterTypes()[0]));
			} catch (Exception e) {
				LOG.error(String.format("配置类[%s]属性[%s]注入失败", object.getClass().getName(), propertyKey), e);
			}
		}
	}

	public static String getKeyByMethod(String prefix, Method method) {
		String key = StrKit.firstCharToLowerCase(method.getName().substring(3));
		if (StrKit.isNotBlank(prefix)) {
			key = prefix.trim() + "." + key;
		}
		return key;
	}
	public static Collection<Method> getClassSetMethods(Class<?> clazz) {
		Method[] methods = clazz.getMethods();
		Collection<Method> setMethods = new HashSet<Method>();
		for (Method method : methods) {
			if (method.getName().startsWith("set") && method.getName().length() > 3
					&& method.getParameterTypes().length == 1) {
				setMethods.add(method);
			}
		}
		return setMethods;
	}

	/**
	 * 返回扫描监听器
	 * @return the listener
	 */
	public static final IConfigScanerLinstener getListener() {
		return listener;
	}
}
